namespace MouseGestures
{
    using System;

    using WinAPI;
    using WinAPI.Hooks;

    ///<summary>
    ///	Captures mouse events necessary for mouse gesture recognition
    ///</summary>
    ///<remarks>
    ///	LLMouseFilter uses Windows Hooks to capture mouse events
    ///</remarks>
    internal class LLMouseFilter : WindowsHook, IDisposable, IMouseMessageFilter
    {
        #region Fields

        private bool enabled;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// 	Initializes new instance of LLMouseFilter
        /// </summary>
        public LLMouseFilter()
            : base(HookType.WH_MOUSE)
        {
            // we provide our own callback function
            this.callbackFunc = new HookCallbackFunction(this.MouseHookCallback);

            this.Install();
        }

        ~LLMouseFilter()
        {
            this.Dispose(false);
        }

        #endregion

        #region Public Events

        /// <summary>
        /// 	Occures when mouse is moved
        /// </summary>
        public event MouseFilterEventHandler MouseMove;

        /// <summary>
        /// 	Occures when right mouse button is pressed
        /// </summary>
        public event MouseFilterEventHandler RightButtonDown;

        /// <summary>
        /// 	Occures when right mouse button is relesed
        /// </summary>
        public event MouseFilterEventHandler RightButtonUp;

        #endregion

        #region Public Properties

        public bool Enabled
        {
            get
            {
                return this.enabled;
            }
            set
            {
                this.enabled = value;
            }
        }

        #endregion

        #region Public Methods and Operators

        public void Dispose()
        {
            this.Dispose(true);
        }

        #endregion

        #region Methods

        protected void Dispose(bool disposing)
        {
            if (this.Installed)
            {
                this.Uninstall();
            }

            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// 	MouseHook callback function. It recives notification about mouse events from the system and
        /// 	filter messages to be passed to the application.
        /// </summary>
        /// <param name="code"> Message code. </param>
        /// <param name="wParam"> Pointer to the wParam structure. </param>
        /// <param name="lParam"> Pointer to the lParam structure. </param>
        /// <returns> </returns>
        protected int MouseHookCallback(int code, IntPtr wParam, IntPtr lParam)
        {
            // according to the Platform SDK a code < 0 means skip
            if (code < 0)
            {
                return CallNextHookEx(this.hhook, code, wParam, lParam);
            }

            // if enabled fillter messages passed to the application
            if ((code == (int)MessageCodes.HC_ACTION) && this.enabled)
            {
                int messageCode = wParam.ToInt32();

                switch (messageCode)
                {
                    case (int)MessageCodes.WM_RBUTTONDOWN:
                        this.RaiseRightButtonDownEvent();

                        //dont let applicaton to recive WM_RBUTTONDOWN message
                        return 1;
                    case (int)MessageCodes.WM_MOUSEMOVE:
                        this.RaiseRightButtonMoveEvent();

                        //let applicaton to recive WM_MOUSEMOVE message
                        break;
                    case (int)MessageCodes.WM_RBUTTONUP:
                        this.RaiseRightButtonUpEvent();

                        //dont let applicaton to recive WM_RBUTTONUP message
                        return 1;
                }
            }

            // Call the next hook in the chain
            return CallNextHookEx(this.hhook, code, wParam, lParam);
        }

        private void RaiseRightButtonDownEvent()
        {
            MouseFilterEventHandler temp = this.RightButtonDown;
            if (temp != null)
            {
                temp(this, EventArgs.Empty);
            }
        }

        private void RaiseRightButtonMoveEvent()
        {
            MouseFilterEventHandler temp = this.MouseMove;
            if (temp != null)
            {
                temp(this, EventArgs.Empty);
            }
        }

        private void RaiseRightButtonUpEvent()
        {
            MouseFilterEventHandler temp = this.RightButtonUp;
            if (temp != null)
            {
                temp(this, EventArgs.Empty);
            }
        }

        #endregion
    }
}